package org.jeecg.modules.quartz.job;

import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.crypto.digest.DigestUtil;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.modules.payment.paymentalipayorder.entity.PaymentAlipayOrder;
import org.jeecg.modules.payment.paymentalipayorder.service.IPaymentAlipayOrderService;
import org.quartz.DisallowConcurrentExecution;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.quartz.QuartzJobBean;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;

import java.lang.reflect.Field;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.Arrays;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

@Slf4j
@DisallowConcurrentExecution
public class CallbackQuartzJobBean  extends QuartzJobBean {

    @Autowired
     private RedisTemplate redisTemplate;
     @Autowired
     private IPaymentAlipayOrderService paymentAlipayOrderService;
     @Autowired
     private RestTemplate restTemplate;

    public static final String CALLBACK_QUEUE="CALLBACK_QUEUE";

    @Override
    protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        long score = System.currentTimeMillis();
        Set<PaymentAlipayOrder> set = redisTemplate.opsForZSet().rangeByScore(CALLBACK_QUEUE, 0, score);
        set.parallelStream().forEach(o -> {
            if(o.getState().equals("N")){
                Field[] fields = ReflectUtil.getFields(PaymentAlipayOrder.class);
                TreeMap treeMap= new TreeMap();
                Arrays.stream(fields).parallel().forEach(field -> {
                    if(ReflectUtil.getFieldValue(o,field)!=null) {
                        treeMap.put(field.getName(), ReflectUtil.getFieldValue(o, field));
                    }
                });
                String secretKey = (String) treeMap.remove("secretKey");
                String callbackUrl = (String) treeMap.remove("callbackUrl");
                StringBuffer stringBuffer=new StringBuffer();
                treeMap.forEach((o1, o2) -> {
                    stringBuffer.append("&"+o1+"="+o2);
                });
                String substring = stringBuffer.substring(1);
                String key = substring + secretKey;
                String signature = DigestUtil.sha256Hex(key);
                try {
                    Map forObject = restTemplate.getForObject(callbackUrl + "?" + substring + "&signature=" + signature, Map.class);
                    if ((Boolean) forObject.get("success")) {
                        o.setState("Y");
                    } else {
                        o.setState("N");
                    }
                }catch (RestClientException restClientException){
                    o.setCallbackNum(o.getCallbackNum() + 1);
                    if(o.getCallbackNum().intValue()==1)
                        redisTemplate.opsForZSet().add(CALLBACK_QUEUE, o, LocalDateTime.now().plusMinutes(3).toInstant(ZoneOffset.ofHours(8)).toEpochMilli());
                    if(o.getCallbackNum().intValue()==2)
                        redisTemplate.opsForZSet().add(CALLBACK_QUEUE, o, LocalDateTime.now().plusHours(1).toInstant(ZoneOffset.ofHours(8)).toEpochMilli());
                    if(o.getCallbackNum().intValue()==3)
                        redisTemplate.opsForZSet().add(CALLBACK_QUEUE, o, LocalDateTime.now().plusDays(1).toInstant(ZoneOffset.ofHours(8)).toEpochMilli());
                }
                paymentAlipayOrderService.saveOrUpdate(o);
            }
        });
        redisTemplate.opsForZSet().removeRangeByScore(CALLBACK_QUEUE,0,score);
    }
}
